package com.cn.onetrip.untility;

import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.net.URL;
import java.util.HashMap;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Bitmap.Config;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Environment;
import android.os.Handler;

public class SyncImageLoader {

	private Object lock = new Object();

	private boolean mAllowLoad = true;

	private boolean firstLoad = true;

	private int mStartLoadLimit = 0;

	private int mStopLoadLimit = 0;

	final Handler handler = new Handler();

	private Context mContext;

	private HashMap<String, SoftReference<Drawable>> imageCache = new HashMap<String, SoftReference<Drawable>>();

	RunInOtherThread runInOutherThread;

	public SyncImageLoader(Context context) {
		super();
		this.mContext = context;
		runInOutherThread = new RunInOtherThread();
		runInOutherThread.start();
	}

	public interface OnImageLoadListener {
		public void onImageLoad(Integer t, Drawable drawable);

		public void onError(Integer t);

		public void onImageLoad(Drawable drawable);

		public void onError();
	}

	public void setLoadLimit(int startLoadLimit, int stopLoadLimit) {
		if (startLoadLimit > stopLoadLimit) {
			return;
		}
		mStartLoadLimit = startLoadLimit;
		mStopLoadLimit = stopLoadLimit;
	}

	public void restore() {
		mAllowLoad = true;
		firstLoad = true;
	}

	public void lock() {
		mAllowLoad = false;
		firstLoad = false;
	}

	public void unlock() {
		mAllowLoad = true;
		synchronized (lock) {
			lock.notifyAll();
		}
	}

	public void loadImage(String imageUrl, OnImageLoadListener listener) {
		final OnImageLoadListener mListener = listener;
		final String mImageUrl = imageUrl;

		Handler handerTest = runInOutherThread.getHandler();
		if (handerTest == null) {
			handerTest = runInOutherThread.getHandler();
		}
		if (handerTest != null) {
			handerTest.post(new Runnable() {
				@Override
				public void run() {
					if (!mAllowLoad) {
						synchronized (lock) {
							try {
								DebugUtil.debug("wait start.....");
								lock.wait();
								DebugUtil.debug("wait end.....");
							} catch (InterruptedException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						}
					}
					if (mAllowLoad) {
						loadImage1(mImageUrl, mListener);
					}
				}
			});
		}
	}

	public void loadImage(Integer t, String imageUrl,
			OnImageLoadListener listener) {
		final OnImageLoadListener mListener = listener;
		final String mImageUrl = imageUrl;
		final Integer mt = t;

		runInOutherThread.getHandler().post(new Runnable() {

			@Override
			public void run() {
				if (!mAllowLoad) {
					synchronized (lock) {
						try {
							DebugUtil.debug("wait start.....");
							lock.wait();
							DebugUtil.debug("wait end.....");
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
				}

				if (mAllowLoad && firstLoad) {
					loadImage(mImageUrl, mt, mListener);
				}

				if (mAllowLoad && mt <= mStopLoadLimit && mt >= mStartLoadLimit) {
					loadImage(mImageUrl, mt, mListener);
				}
			}

		});
	}

	private void loadImage(final String mImageUrl, final Integer mt,
			final OnImageLoadListener mListener) {

		if (imageCache.containsKey(mImageUrl)) {
			SoftReference<Drawable> softReference = imageCache.get(mImageUrl);
			final Drawable d = softReference.get();
			if (d != null) {
				handler.post(new Runnable() {
					@Override
					public void run() {
						if (mAllowLoad) {
							mListener.onImageLoad(mt, d);
						}
					}
				});
				return;
			}
		}
		try {
			final Drawable d = loadImageFromUrl(mImageUrl);
			if (d != null) {
				imageCache.put(mImageUrl, new SoftReference<Drawable>(d));
			}
			handler.post(new Runnable() {
				@Override
				public void run() {
					if (mAllowLoad) {
						mListener.onImageLoad(mt, d);
					}
				}
			});
		} catch (IOException e) {
			handler.post(new Runnable() {
				@Override
				public void run() {
					mListener.onError(mt);
				}
			});
			e.printStackTrace();
		}
	}

	private void loadImage1(final String mImageUrl,
			final OnImageLoadListener mListener) {

		if (imageCache.containsKey(mImageUrl)) {
			SoftReference<Drawable> softReference = imageCache.get(mImageUrl);
			final Drawable d = softReference.get();
			if (d != null) {
				handler.post(new Runnable() {
					@Override
					public void run() {
						if (mAllowLoad) {
							mListener.onImageLoad(d);
						}
					}
				});
				return;
			} else {
				imageCache.remove(mImageUrl);
			}
		}
		try {
			final Drawable d = loadImageFromUrl(mImageUrl);
			if (d != null) {
				imageCache.put(mImageUrl, new SoftReference<Drawable>(d));
			}
			handler.post(new Runnable() {
				@Override
				public void run() {
					if (mAllowLoad) {
						mListener.onImageLoad(d);
					}
				}
			});

		} catch (IOException e) {
			handler.post(new Runnable() {
				@Override
				public void run() {
					mListener.onError();
				}
			});
			e.printStackTrace();
		}
	}

	public static Drawable loadImageFromUrl(String url) throws IOException {
		// DebugUtil.debug(url);
		if (url == null || url.length() == 0)
			return null;

//		DebugUtil.debug(url);
		File file = new File(url);
		Bitmap bitmap = null;
		Drawable drawable = null;
		if (file.exists()) {
			FileInputStream fis = new FileInputStream(file);
			try {
				bitmap = BitmapFactory.decodeStream(fis);
			} catch (OutOfMemoryError e) {
				BitmapFactory.Options options = new BitmapFactory.Options();
				options.inSampleSize = 4;
				options.inPreferredConfig = Config.RGB_565;
				try {
					bitmap = BitmapFactory.decodeStream(fis, null, options);
				} catch (OutOfMemoryError e2) {
					return null;
				}
			} finally {
				if (fis != null) {
					fis.close();
					System.gc();
				}
			}
			if (bitmap != null) {
				drawable = new BitmapDrawable(bitmap);
			}
			return drawable;
		} else {
			File f = new File(HTTPUrl.ImageCacheFloder + "/" + MD5.getMD5(url));
			if (f.exists()) {
				FileInputStream fis = new FileInputStream(f);
				try {
					bitmap = BitmapFactory.decodeStream(fis);
				} catch (OutOfMemoryError err) {
					BitmapFactory.Options opt = new BitmapFactory.Options();
					opt.inPreferredConfig = Bitmap.Config.RGB_565;
					opt.inSampleSize = 4;
					try {
						bitmap = BitmapFactory.decodeStream(fis, null, opt);
					} catch (OutOfMemoryError e) {
						return null;
					}
				} finally {
					if (fis != null) {
						fis.close();
						System.gc();
					}
				}
				if (bitmap != null) {
					drawable = new BitmapDrawable(bitmap);
				} else {
					HTTPUrl.deleteFile(f);
					return loadImageFromUrl(url);
				}
				return drawable;
			}
			URL m = new URL(url);
			InputStream i = (InputStream) m.getContent();

			try {
				DataInputStream in = new DataInputStream(i);
				FileOutputStream out = new FileOutputStream(f);
				byte[] buffer = new byte[1024];
				int byteread = 0;
				while ((byteread = in.read(buffer)) != -1) {
					out.write(buffer, 0, byteread);
				}

				out.close();
				in.close();
				i.close();
				return loadImageFromUrl(url);

			} catch (Exception e) {
				// Drawable d = Drawable.createFromStream(i, "src");

				Bitmap bmp = BitmapFactory.decodeStream(i);
				Drawable d = new BitmapDrawable(bmp);
				i.close();
				return d;
			}
		}
	}

	public void threadQuit() {
		// TODO Auto-generated method stub
		if (runInOutherThread != null) {
			runInOutherThread.quit();
		}

	}
}
